package cn.edu.csust.coursecard.service.impl;

import cn.edu.csust.coursecard.common.CodeEnum;
import cn.edu.csust.coursecard.dao.AssociationMapper;
import cn.edu.csust.coursecard.dao.dto.RedisKeyConstant;
import cn.edu.csust.coursecard.dao.entity.Association;
import cn.edu.csust.coursecard.dao.entity.AssociationCategory;
import cn.edu.csust.coursecard.exception.BaseException;
import cn.edu.csust.coursecard.service.IAssociationService;
import cn.edu.csust.coursecard.utils.storage.FileUtils;
import cn.edu.csust.coursecard.utils.storage.StorageUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class AssociationServiceImpl implements IAssociationService {

    @Autowired
    private AssociationMapper associationMapper;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Resource
    private StorageUtils storageUtils;


    @Override
    @Transactional
    public void addCategory(AssociationCategory category) {

        AssociationCategory result = associationMapper.selectCategoryByName(category.getCategoryName());
        if (result != null) {
            throw new BaseException(CodeEnum.PARAM_ERROR.getCode(), "该分类已存在");
        }
        int rows = associationMapper.insertCategory(category);
        if (rows != 1) {
            throw new BaseException(CodeEnum.SYSTEM_ERROR.getCode(), "添加分类失败");
        }
        redisTemplate.delete(RedisKeyConstant.CATEGORY);
    }

    @Override
    public List<AssociationCategory> getAllCategory() {
        List<Object> objectList = redisTemplate.opsForHash().values(RedisKeyConstant.CATEGORY);
        if (CollectionUtils.isEmpty(objectList)) {
            List<AssociationCategory> categoryList = associationMapper.selectAllCategory();
            if (!CollectionUtils.isEmpty(categoryList)) {
                Map<Integer, Object> map = new HashMap<>();
                categoryList.forEach(obj -> map.put(obj.getId(), obj));
                redisTemplate.opsForHash().putAll(RedisKeyConstant.CATEGORY, map);
                redisTemplate.expire(RedisKeyConstant.CATEGORY, 7, TimeUnit.DAYS);
            }
            return categoryList;
        }

        return objectList.stream().map(obj -> (AssociationCategory) obj).collect(Collectors.toList());
    }

    @Override
    @Transactional
    public void deleteCategory(Integer categoryId) {
        checkCategoryId(categoryId);
        int rows = associationMapper.deleteCategory(categoryId);
        if (rows != 1) {
            throw new BaseException(CodeEnum.SYSTEM_ERROR.getCode(), "删除分类失败");
        }
        redisTemplate.delete(RedisKeyConstant.CATEGORY);
    }

    @Override
    @Transactional
    public void addAssociation(Association association, MultipartFile file) {
        if (StringUtils.isEmpty(association.getName())
                || StringUtils.isEmpty(association.getIntroduce())) {
            throw new BaseException(CodeEnum.PARAM_ERROR.getCode(), "请完善社团基本信息");
        }
        checkCategoryId(association.getCategoryId());
        String newFileName = "association/" + FileUtils.createFileName(file);
        association.setIcon(storageUtils.getUrl() + newFileName);
        Date date = new Date();
        association.setCreateTime(date).setUpdateTime(date).setIsValid(true);
        int rows = associationMapper.insertAssociationSelective(association);
        if (rows != 1) {
            throw new BaseException(CodeEnum.SYSTEM_ERROR.getCode(), "社团添加失败");
        }
        storageUtils.upload(file, newFileName);
        redisTemplate.delete(RedisKeyConstant.ASS_CATE + association.getCategoryId());
    }

    @Override
    public void deleteAssociation(Integer id) {
        Association association = associationMapper.selectAssociationByPrimaryKey(id);
        if (association == null) {
            throw new BaseException(CodeEnum.PARAM_ERROR.getCode(), "删除的社团id错误");
        }
        Association update = new Association().setId(id).setUpdateTime(new Date()).setIsValid(false);
        int i = associationMapper.updateAssoiationByPrimaryKeySelective(update);
        if (i != 1) {
            throw new BaseException(CodeEnum.SYSTEM_ERROR.getCode(), "删除社团失败");
        }
        redisTemplate.delete(RedisKeyConstant.ASS_CATE + association.getCategoryId());
    }

    @Override
    public List<Association> getAssociationByCategory(Integer categoryId) {
        checkCategoryId(categoryId);
        Set<Object> objectSet = redisTemplate.opsForSet().members(RedisKeyConstant.ASS_CATE + categoryId);
        if (CollectionUtils.isEmpty(objectSet)) {
            List<Association> associations = associationMapper.selectAssociation(categoryId);
            if (!CollectionUtils.isEmpty(associations)) {
                redisTemplate.opsForSet().add(RedisKeyConstant.ASS_CATE + categoryId, associations.toArray());
            }
            return associations;
        }
        return objectSet.stream().map(obj -> (Association) obj).collect(Collectors.toList());
    }

    @Override
    public List<Association> getAllAssociation() {
        return associationMapper.selectAssociation(null);
    }

    private void checkCategoryId(Integer categoryId) {
        Boolean hasKey = redisTemplate.opsForHash().hasKey(RedisKeyConstant.CATEGORY, categoryId);
        if (!hasKey) {
            throw new BaseException(CodeEnum.PARAM_ERROR.getCode(), "没有该分类");
        }
    }
}
